using System.Security.Claims;
using IdentityModel;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;

using Leo.Core.Identity.Contracts;
using Leo.Core.Jwt;

using Volo.Abp.Caching;
using Volo.Abp.Security.Claims;

namespace Leo.Core.Identity
{
    public class ConfigIdentityCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor
    {
        private readonly IOptions<ConfigIdentityOptions> _identityConfigOptions;
        private readonly IDistributedCache<JwtTokenCacheItem> _distributedCache;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ITokenService _tokenService;

        public ConfigIdentityCurrentPrincipalAccessor(
             IOptions<ConfigIdentityOptions> identityConfigOptions,
             IDistributedCache<JwtTokenCacheItem> distributedCache,
             IHttpContextAccessor httpContextAccessor,
             ITokenService tokenService)
        {
            _identityConfigOptions = identityConfigOptions;
            _distributedCache = distributedCache;
            _httpContextAccessor= httpContextAccessor;
            _tokenService= tokenService;
        }


        protected override ClaimsPrincipal GetClaimsPrincipal()
        {
            var claimsPrincipal = _httpContextAccessor.HttpContext?.User;
            if (claimsPrincipal == null || !claimsPrincipal.Claims.Any())
            {
                return base.GetClaimsPrincipal();
            }
            var userid = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == AbpClaimTypes.UserId)?.Value;
            var tenantId = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == AbpClaimTypes.TenantId)?.Value;
            var guidUserId = userid == null ? Guid.Empty : Guid.Parse(userid);
            Guid? guidTenantId = string.IsNullOrWhiteSpace(tenantId) ? null : Guid.Parse(tenantId);

            var key = new JwtTokenCacheKey(guidUserId, guidTenantId);
            var cacheItem = _distributedCache.Get(key.ToString());
            if (cacheItem == null || cacheItem.Token.IsNullOrEmpty())
            {
                var token = _tokenService.GenerateAccessToken(GenerateClaim(claimsPrincipal));
                cacheItem = new JwtTokenCacheItem(token);
                 _distributedCache.Set(key.ToString(), cacheItem);
            }
            return claimsPrincipal;
        }

        private Claim[] GenerateClaim(ClaimsPrincipal claimsPrincipal)
        {
            var claims = new List<Claim>();
            claims.Add(new Claim(AbpClaimTypes.UserName, FindClaimVaule(AbpClaimTypes.UserName)));
            claims.Add(new Claim(AbpClaimTypes.UserId, FindClaimVaule(AbpClaimTypes.UserId)));
            claims.Add(new Claim(AbpClaimTypes.Email, FindClaimVaule(AbpClaimTypes.Email)));
            claims.Add(new Claim(AbpClaimTypes.PhoneNumber, FindClaimVaule(AbpClaimTypes.PhoneNumber)));
            claims.Add(new Claim(AbpClaimTypes.TenantId, FindClaimVaule(AbpClaimTypes.TenantId)));
            claims.Add(new Claim(AbpClaimTypes.Role, FindClaimVaule(AbpClaimTypes.Role)));
            string FindClaimVaule(string claimType)
            {
                var claim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == claimType);
                if (claim != null)
                {
                    return claim.Value;
                }
                return string.Empty;
            }
            return claims.ToArray();
        }
    }
}
